﻿using System;
using System.Collections.Generic;

namespace Srk.BetaseriesApi {

    /// <summary>
    /// Represents the betaseries.com API.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
    public interface IBetaseriesApi : IDisposable {

        /// <summary>
        /// Recommended field for application tracking.
        /// </summary>
        string UserAgent { get; set; }

        /// <summary>
        /// API Key required for all queries.
        /// </summary>
        string Key { get; set; }

        /// <summary>
        /// Session username when using authenticated queries.
        /// </summary>
        string SessionUsername { get; }

        /// <summary>
        /// Session token when using authenticated queries.
        /// </summary>
        string SessionToken { get; }

        /// <summary>
        /// Set new session tokens.
        /// </summary>
        /// <param name="newSessionToken"></param>
        /// <param name="newSessionUsername"></param>
        void SetSessionTokens(string newSessionToken, string newSessionUsername);

        #region Shows

        /// <summary>
        /// Search for shows.
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        void SearchShowsAsync(string title);

        event AsyncResponseHandler<IList<Show>> SearchShowsEnded;

        /// <summary>
        /// Get a show's information.
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        void GetShowAsync(string url);

        event AsyncResponseHandler<Show> GetShowEnded;

        /// <summary>
        /// Get a list of all shows.
        /// </summary>
        /// <returns></returns>
        void GetShowsAsync();

        event AsyncResponseHandler<IList<Show>> GetShowsEnded;

        /// <summary>
        /// Get all episodes from a show.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <returns></returns>
        void GetEpisodesAsync(string showUrl);

        /// <summary>
        /// Get all episodes from a show and season.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <returns></returns>
        void GetEpisodesAsync(string showUrl, uint season);

        event AsyncResponseHandler<IList<Episode>> GetEpisodesEnded;

        /// <summary>
        /// Get 1 episode from a show.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <param name="episode"></param>
        /// <returns></returns>
        void GetEpisodeAsync(string showUrl, uint season, uint episode);

        event AsyncResponseHandler<Episode> GetEpisodeEnded;

        #region For the current user

        /// <summary>
        /// Add a show to your account.
        /// You must have a valid session <see cref="SessionToken"/>.
        /// </summary>
        /// <param name="showUrl"></param>
        void AddShowAsync(string showUrl);

        event AsyncResponseHandler AddShowEnded;

        /// <summary>
        /// Remove a show from your account.
        /// You must have a valid session <see cref="SessionToken"/>.
        /// </summary>
        /// <param name="showUrl"></param>
        void RemoveShowAsync(string showUrl);

        event AsyncResponseHandler RemoveShowEnded;

        #endregion

        #endregion

        #region Subtitles

        /// <summary>
        /// Get the  subtitles for a show.
        /// </summary>
        /// <param name="showUrl">Show's url (required)</param>
        /// <param name="language">"VO" or "VF" or null for all languages</param>
        /// <param name="season">a season number or null for all seasons</param>
        /// <param name="episode">an episode number or null for all episodes</param>
        /// <returns></returns>
        void GetShowSubtitlesAsync(string showUrl, string language, uint? season, uint? episode);

        event AsyncResponseHandler<IList<Subtitle>> GetShowSubtitlesEnded;

        /// <summary>
        /// Get the latest subtitles.
        /// </summary>
        /// <returns></returns>
        void GetLatestSubtitlesAsync();

        /// <summary>
        /// Get the latest subtitles.
        /// </summary>
        /// <param name="language">VO / VF</param>
        /// <returns></returns>
        void GetLatestSubtitlesAsync(string language);

        /// <summary>
        /// Get the latest subtitles.
        /// </summary>
        /// <param name="language">VO / VF</param>
        /// <param name="number"></param>
        /// <returns></returns>
        void GetLatestSubtitlesAsync(string language, uint number);

        event AsyncResponseHandler<IList<Subtitle>> GetLatestSubtitlesEnded;

        /// <summary>
        /// Get the latest subtitles for a show.
        /// </summary>
        /// <param name="showUrl">Show's url</param>
        /// <returns></returns>
        void GetLatestShowSubtitlesAsync(string showUrl);

        /// <summary>
        /// Get the latest subtitles for a show.
        /// </summary>
        /// <param name="showUrl">Show's url</param>
        /// <param name="language">VO / VF</param>
        /// <returns></returns>
        void GetLatestShowSubtitlesAsync(string showUrl, string language);

        /// <summary>
        /// Get the latest subtitles for a show.
        /// </summary>
        /// <param name="showUrl">Show's url</param>
        /// <param name="language">VO / VF</param>
        /// <param name="number"></param>
        /// <returns></returns>
        void GetLatestShowSubtitlesAsync(string showUrl, string language, uint number);

        event AsyncResponseHandler<IList<Subtitle>> GetLatestShowSubtitlesEnded;

        #endregion

        #region Planning

        /// <summary>
        /// Fetch all episodes from the last 8 days to the next 8 days.
        /// </summary>
        /// <returns></returns>
        void GetPlanningAsync();

        event AsyncResponseHandler<IList<Episode>> GetPlanningEnded;

        /// <summary>
        /// Fetch episodes from a member's agenda and from the last 8 days to the next 8 days.
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        void GetMembersPlanningAsync(string username);

        /// <summary>
        /// Fetch episodes from a member's agenda and from the last 8 days to the next 8 days.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="unseenOnly">if true, only fetch unseem episodes</param>
        /// <returns></returns>
        void GetMembersPlanningAsync(string username, bool unseenOnly);

        event AsyncResponseHandler<IList<Episode>> GetMembersPlanningEnded;

        #endregion

        #region Members

        /// <summary>
        /// Authenticate a user.
        /// This will set the received token in the <see cref="SessionToken"/> property.
        /// This will set the username in the <see cref="SessionUsername"/> property.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        void AuthenticateAsync(string username, string password);

        event AsyncResponseHandler<string> AuthenticateEnded;

        /// <summary>
        /// Verify the session is still active.
        /// </summary>
        void GetIsSessionActiveAsync();

        event AsyncResponseHandler<bool> GetIsSessionActiveEnded;

        /// <summary>
        /// Log-off. 
        /// This will unset the <see cref="SessionToken"/> property.
        /// This will unset the <see cref="SessionUsername"/> property.
        /// </summary>
        void LogoffAsync();

        event AsyncResponseHandler LogoffEnded;

        /// <summary>
        /// Get a member's informations.
        /// </summary>
        /// <param name="username">if null, it will use the <see cref="SessionUsername"/> property's value</param>
        /// <returns></returns>
        void GetMemberAsync(string username);

        event AsyncResponseHandler<Member> GetMemberEnded;

        /// <summary>
        /// Get member's next episodes to watch.
        /// </summary>
        /// <param name="onlyNextEpisode">
        /// if true, only next 1 episode per show is fetched.
        /// if false, all next episodes are fetched.
        /// </param>
        /// <returns></returns>
        void GetMembersNextEpisodesAsync(bool onlyNextEpisode);

        event AsyncResponseHandler<IList<Episode>> GetMembersNextEpisodesEnded;

        /// <summary>
        /// Get member's next episodes to watch for a specific show.
        /// </summary>
        /// <param name="onlyNextEpisode">
        /// if true, only next 1 episode per show is fetched.
        /// if false, all next episodes are fetched.
        /// </param>
        /// <param name="showUrl"></param>
        void GetMembersNextShowEpisodeAsync(bool onlyNextEpisode, string showUrl);

        event AsyncResponseHandler<Episode> GetMembersNextShowEpisodeEnded;

        /// <summary>
        /// Set the latest seen episode of a show.
        /// All previous shows will be marked as seen because the website does not support per-episode seen-flag.
        /// If you pass season=0 and episode=0, the show will be marked as unseen.
        /// Only works if the <see cref="SessionToken"/> is set and valid.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <param name="episode"></param>
        /// <param name="mark">null or a number from 1 to 5</param>
        /// <returns></returns>
        void SetEpisodeAsSeenAsync(string showUrl, uint season, uint episode, ushort? mark);

        event AsyncResponseHandler SetEpisodeAsSeenEnded;

        /// <summary>
        /// Set the latest downloaded episode of a show.
        /// Only works if the <see cref="SessionToken"/> is set and valid.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <param name="episode"></param>
        void SetEpisodeAsDownloadedAsync(string showUrl, uint season, uint episode);

        event AsyncResponseHandler SetEpisodeAsDownloadedEnded;

        /// <summary>
        /// Set a mark for an episode.
        /// Only works if the <see cref="SessionToken"/> is set and valid.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <param name="episode"></param>
        /// <param name="mark">null or a number from 1 to 5</param>
        void SetEpisodeMarkAsync(string showUrl, uint season, uint episode, ushort mark);

        event AsyncResponseHandler SetEpisodeMarkEnded;

        /// <summary>
        /// Returns user's notifications.
        /// </summary>
        /// <param name="seen">null for all, false for new ones, true for old ones</param>
        /// <param name="count"></param>
        /// <param name="fromNotificationId"></param>
        void GetNotificationsAsync(bool? seen, uint? count, uint? fromNotificationId);

        event AsyncResponseHandler<IList<Notification>> GetNotificationsEnded;

        /// <summary>
        /// Create a new account.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="email"></param>
        void SignupAsync(string username, string password, string email);

        event AsyncResponseHandler SignupEnded;

        /// <summary>
        /// Returns a user's friends.
        /// </summary>
        /// <param name="username">current member if null</param>
        /// <returns></returns>
        void GetFriendsAsync(string username);

        event AsyncResponseHandler<IList<string>> GetFriendsEnded;

        /// <summary>
        /// Returns user's badges.
        /// </summary>
        /// <param name="username"></param>
        void GetBadgesAsync(string username);

        event AsyncResponseHandler<string[]> GetBadgesEnded;

        #endregion

        #region Comments

        /// <summary>
        /// Fetch comments for a TV show.
        /// </summary>
        /// <param name="showUrl"></param>
        void GetCommentsForShowAsync(string showUrl);

        event AsyncResponseHandler<IList<Comment>> GetCommentsForShowEnded;

        /// <summary>
        /// Fetch comments for an episode.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <param name="episode"></param>
        void GetCommentsForEpisodeAsync(string showUrl, uint season, uint episode);

        event AsyncResponseHandler<IList<Comment>> GetCommentsForEpisodeEnded;

        /// <summary>
        /// Fetch comments for a member.
        /// </summary>
        /// <param name="username"></param>
        void GetCommentsForMemberAsync(string username);

        event AsyncResponseHandler<IList<Comment>> GetCommentsForMemberEnded;

        /// <summary>
        /// Post a comment on a TV show.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="comment"></param>
        /// <param name="inReplyTo"></param>
        void CommentShowAsync(string showUrl, string comment, uint? inReplyTo);

        event AsyncResponseHandler CommentShowEnded;

        /// <summary>
        /// Post a comment on an episode.
        /// </summary>
        /// <param name="showUrl"></param>
        /// <param name="season"></param>
        /// <param name="episode"></param>
        /// <param name="comment"></param>
        /// <param name="inReplyTo"></param>
        void CommentEpisodeAsync(string showUrl, uint season, uint episode, string comment, uint? inReplyTo);

        event AsyncResponseHandler CommentEpisodeEnded;

        /// <summary>
        /// Post a comment on a member.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="comment"></param>
        /// <param name="inReplyTo"></param>
        void CommentMemberAsync(string username, string comment, uint? inReplyTo);

        event AsyncResponseHandler CommentMemberEnded;

        #endregion

        #region Timeline

        /// <summary>
        /// Returns the main timeline (from all members).
        /// </summary>
        /// <param name="count"></param>
        void GetMainTimelineAsync(uint? count);

        event AsyncResponseHandler<IList<TimelineItem>> GetMainTimelineEnded;

        /// <summary>
        /// Returns the friends timeline (from all friends of the current user).
        /// </summary>
        /// <param name="count"></param>
        void GetFriendsTimelineAsync(uint? count);

        event AsyncResponseHandler<IList<TimelineItem>> GetFriendsTimelineEnded;

        /// <summary>
        /// Returns a member's timeline.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="count"></param>
        void GetMemberTimelineAsync(string username, uint? count);

        event AsyncResponseHandler<IList<TimelineItem>> GetMemberTimelineEnded;

        #endregion

    }
}
